package com.macro.mall.commission.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.macro.mall.commission.domain.OrderSettle;
import com.macro.mall.commission.entity.OrderPredicateEntity;
import com.macro.mall.commission.entity.OrderSettleEntity;
import com.macro.mall.commission.enums.UserBalanceChangeChangeTypeEnum;
import com.macro.mall.commission.event.OrderPredicateEvent;
import com.macro.mall.commission.event.OrderPredicateEventArg;
import com.macro.mall.commission.mapper.OrderSettleMapper;
import com.macro.mall.commission.service.AssignService;
import com.macro.mall.commission.service.OrderPredicateService;
import com.macro.mall.commission.service.OrderSettleService;
import com.macro.mall.commission.service.UserBalanceChangeService;
import com.macro.mall.commission.service.bo.*;
import com.macro.mall.common.api.exception.BusinessException;
import com.macro.mall.oms.entity.OrderEntity;
import com.macro.mall.oms.service.order.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * 订单佣金结算Service
 *
 * @author xuyanjun
 * @date 2019-12-11
 */
@Slf4j
@Service
public class OrderSettleServiceImpl extends ServiceImpl<OrderSettleMapper, OrderSettleEntity> implements OrderSettleService, ApplicationEventPublisherAware {

    @Autowired
    private OrderSettleMapper orderSettleMapper;

    @Autowired
    private OrderService orderService;

    @Autowired
    private AssignService assignService;

    @Autowired
    private UserBalanceChangeService userBalanceChangeService;

    @Autowired
    private OrderPredicateService orderPredicateService;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    private ExecutorService executorService = Executors.newFixedThreadPool(1);

    /**
     * 结算
     *
     * @param orderId 订单id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void settle(long orderId) {
        OrderEntity order = orderService.getById(orderId);
        Assert.notNull(order, String.format("未找到订单id为:%s的订单。", orderId));

        if (isOrderSettled(orderId)) {
            throw new BusinessException(String.format("生活订单id:%s已经存在结算的记录，不能进行结算。", orderId));
        }

        List<AssignItemBo> assignItemBos = assignService.listAssignItem(orderId, 1);
        List<OrderSettleEntity> settleEntities = createSettleEntities(assignItemBos);

        saveBatch(settleEntities);

        orderService.updateSettleStatus(orderId, 10);

        List<OrderSettleEntity> orderSettleEntities = listByOrderId(orderId);

        Map<Long, List<OrderSettleEntity>> groups = orderSettleEntities.stream().filter(x->x.getUserId()>0).collect(Collectors.groupingBy(OrderSettleEntity::getUserId));
        groups.forEach((userId, v) -> {
            int sum = v.stream().mapToInt(OrderSettleEntity::getAmount).sum();

            InsertUserBalanceChangeInput insertUserBalanceChangeInput = new InsertUserBalanceChangeInput();
            insertUserBalanceChangeInput
                    .setUserId(userId)
                    .setChangeAmount(sum)
                    .setChangeTypeEnum(UserBalanceChangeChangeTypeEnum.COMMISSION_INCOME);

            userBalanceChangeService.insert(insertUserBalanceChangeInput);
        });

        List<Long> ids = orderSettleEntities.stream().map(OrderSettleEntity::getId).collect(Collectors.toList());

        completeSettle(ids);

        List<Long> predicateIds = settleEntities.stream().map(OrderSettleEntity::getId).collect(Collectors.toList());

        OrderPredicateEventArg eventArg = new OrderPredicateEventArg();
        eventArg.setPredicateIds(predicateIds);

        OrderPredicateEvent event = new OrderPredicateEvent(this, eventArg);

        executorService.execute(() -> {
            applicationEventPublisher.publishEvent(event);
        });

       // orderPredicateService.updateSettledByOrderId(orderId);
    }

    /**
     * 指定的订单id是否已结算过
     *
     * @param orderId 订单id
     * @return 是否已结算过
     */
    private boolean isOrderSettled(long orderId) {
        LambdaQueryWrapper<OrderSettleEntity> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(OrderSettleEntity::getOrderId, orderId);

        int count = orderSettleMapper.selectCount(queryWrapper);
        return count > 0;
    }

    /**
     * 创建结算实体
     *
     * @param assignItemBos 分佣条目
     * @return 结算实体
     */
    @SuppressWarnings("Duplicates")
    private List<OrderSettleEntity> createSettleEntities(List<AssignItemBo> assignItemBos) {
        List<OrderSettleEntity> result = new ArrayList<>();

        for (AssignItemBo assignItemBo : assignItemBos) {
            OrderSettleEntity liveOrderSettleEntity = new OrderSettleEntity();
            liveOrderSettleEntity.setAmount(assignItemBo.getAmount())
                    .setAssignType(assignItemBo.getAssignType())
                    .setAssignTypeName(assignItemBo.getAssignTypeName())
                    .setOrderId(assignItemBo.getOrderId())
                    .setOrderNo(assignItemBo.getOrderNo())
                    .setOrderAmount(assignItemBo.getOrderAmount())
                    .setOrderPaymentTime(assignItemBo.getOrderPaymentTime())
                    .setOrderCompleteTime(assignItemBo.getOrderCompleteTime())
                    .setOrderUserId(assignItemBo.getOrderUserId())
                    .setOrderUserName(assignItemBo.getOrderUserName())
                    .setPercent(assignItemBo.getPercent())
                    .setUserId(assignItemBo.getUserId())
                    .setArrivedStatus(0)
                    .setUserName(assignItemBo.getUserName())
                    .setRemark(assignItemBo.getRemark());

            LocalDateTime now = LocalDateTime.now();
            liveOrderSettleEntity.setCreateTime(now);
            liveOrderSettleEntity.setUpdateTime(now);

            result.add(liveOrderSettleEntity);
        }
        return result;
    }

    /**
     * 新增订单佣金结算
     *
     * @param input input
     * @return 新增id
     */
    @Override
    public long insert(InsertOrderSettleInput input) {
        OrderSettleEntity orderSettleEntity = new OrderSettleEntity();
        orderSettleEntity.setArrivedStatus(input.getArrivedStatus())
                .setUserId(input.getUserId())
                .setUserName(input.getUserName())
                .setOrderId(input.getOrderId())
                .setOrderNo(input.getOrderNo())
                .setOrderUserId(input.getOrderUserId())
                .setOrderUserName(input.getOrderUserName())
                .setOrderPaymentTime(input.getOrderPaymentTime())
                .setOrderCompleteTime(input.getOrderCompleteTime())
                .setOrderAmount(input.getOrderAmount())
                .setAmount(input.getAmount())
                .setPercent(input.getPercent())
                .setAssignType(input.getAssignType())
                .setAssignTypeName(input.getAssignTypeName())
                .setRemark(input.getRemark());

        LocalDateTime now = LocalDateTime.now();
        orderSettleEntity.setCreateTime(now);
        orderSettleEntity.setUpdateTime(now);

        orderSettleMapper.insert(orderSettleEntity);
        return orderSettleEntity.getId();
    }

    /**
     * 修改订单佣金结算
     *
     * @param input input
     */
    @Override
    public void update(UpdateOrderSettleInput input) {
        OrderSettleEntity orderSettleEntity = orderSettleMapper.selectById(input.getId());
        if (orderSettleEntity == null) {
            throw new BusinessException(String.format("未能根据Id:%s找到指定的订单佣金结算。", input.getId()));
        }

        orderSettleEntity = new OrderSettleEntity();
        orderSettleEntity
                .setId(input.getId())
                .setArrivedStatus(input.getArrivedStatus())
                .setUserId(input.getUserId())
                .setUserName(input.getUserName())
                .setOrderId(input.getOrderId())
                .setOrderNo(input.getOrderNo())
                .setOrderUserId(input.getOrderUserId())
                .setOrderUserName(input.getOrderUserName())
                .setOrderPaymentTime(input.getOrderPaymentTime())
                .setOrderCompleteTime(input.getOrderCompleteTime())
                .setOrderAmount(input.getOrderAmount())
                .setAmount(input.getAmount())
                .setPercent(input.getPercent())
                .setAssignType(input.getAssignType())
                .setAssignTypeName(input.getAssignTypeName())
                .setRemark(input.getRemark());

        LocalDateTime now = LocalDateTime.now();
        orderSettleEntity.setUpdateTime(now);

        orderSettleMapper.updateById(orderSettleEntity);
    }


    /**
     * 完成结算
     *
     * @param batchIds 批量id
     * @return 是否成功
     */
    private void completeSettle(List<Long> batchIds) {
        if (batchIds.size() <= 0) {
            return;
        }

        orderSettleMapper.updateArrivedStatus(batchIds, 5);
    }

    /**
     * 删除订单佣金结算
     *
     * @param id id
     */
    @Override
    public void delete(long id) {
        orderSettleMapper.deleteById(id);
    }

    /**
     * 根据Id获取订单佣金结算
     *
     * @param id id
     * @return 订单佣金结算
     */
    @Override
    public OrderSettleEntity getById(long id) {
        return orderSettleMapper.selectById(id);
    }

    /**
     * 根据批量Id获取订单佣金结算
     *
     * @param batchIds 批量ids
     * @return 订单佣金结算集合
     */
    @Override
    public List<OrderSettleEntity> listByBatchIds(List<Long> batchIds) {
        if (batchIds == null || batchIds.isEmpty()) {
            return new ArrayList<>();
        }
        return orderSettleMapper.selectBatchIds(batchIds);
    }

    /**
     * 根据订单Id获取订单佣金结算
     *
     * @param orderId 订单Id
     * @return 订单佣金结算集合
     */
    @Override
    public List<OrderSettleEntity> listByOrderId(long orderId) {
        LambdaQueryWrapper<OrderSettleEntity> queryWrapper = Wrappers.lambdaQuery();

        queryWrapper.eq(OrderSettleEntity::getOrderId, orderId);

        return orderSettleMapper.selectList(queryWrapper);
    }

    /**
     * 获取所有未到账的结算记录
     *
     * @param createTimeEndTime   创建时间开始时间
     * @param createTimeBeginTime 创建时间结束时间
     * @return 生活订单佣金分配结算
     */
    @Override
    public List<OrderSettleEntity> listUnArrived(LocalDateTime createTimeBeginTime, LocalDateTime createTimeEndTime) {
        LambdaQueryWrapper<OrderSettleEntity> queryWrapper = Wrappers.lambdaQuery();

        queryWrapper.gt(OrderSettleEntity::getCreateTime, createTimeBeginTime);
        queryWrapper.le(OrderSettleEntity::getCreateTime, createTimeEndTime);
        queryWrapper.eq(OrderSettleEntity::getArrivedStatus, 0);

        return orderSettleMapper.selectList(queryWrapper);
    }

    /**
     * 分页查询
     *
     * @param input input
     * @return 分页的订单佣金结算
     */
    @Override
    public Page<OrderSettleEntity> pagedQuery(PagedQueryOrderSettleInput input) {
        LambdaQueryWrapper<OrderSettleEntity> queryWrapper = Wrappers.lambdaQuery();

        PageHelper.startPage(input.getPageIndex(), input.getPageSize());

        return (Page<OrderSettleEntity>) orderSettleMapper.selectList(queryWrapper);
    }

    /**
     * 将实体对象转换成domain对象
     *
     * @param orderSettleEntity 实体
     * @return orderSettle
     */
    @Override
    public OrderSettle entityToDomain(OrderSettleEntity orderSettleEntity) {
        if (orderSettleEntity == null) {
            return null;
        }

        OrderSettle orderSettle = new OrderSettle();
        orderSettle.setId(orderSettleEntity.getId())
                .setCreateTime(orderSettleEntity.getCreateTime())
                .setUpdateTime(orderSettleEntity.getUpdateTime())
                .setArrivedStatus(orderSettleEntity.getArrivedStatus())
                .setUserId(orderSettleEntity.getUserId())
                .setUserName(orderSettleEntity.getUserName())
                .setOrderId(orderSettleEntity.getOrderId())
                .setOrderNo(orderSettleEntity.getOrderNo())
                .setOrderUserId(orderSettleEntity.getOrderUserId())
                .setOrderUserName(orderSettleEntity.getOrderUserName())
                .setOrderPaymentTime(orderSettleEntity.getOrderPaymentTime())
                .setOrderCompleteTime(orderSettleEntity.getOrderCompleteTime())
                .setOrderAmount(orderSettleEntity.getOrderAmount())
                .setAmount(orderSettleEntity.getAmount())
                .setPercent(orderSettleEntity.getPercent())
                .setAssignType(orderSettleEntity.getAssignType())
                .setAssignTypeName(orderSettleEntity.getAssignTypeName())
                .setRemark(orderSettleEntity.getRemark());

        return orderSettle;
    }

    /**
     * 将实体对象转换成domain对象
     *
     * @param orderSettleEntities 实体
     * @return orderSettles
     */
    @Override
    public List<OrderSettle> entityToDomain(List<OrderSettleEntity> orderSettleEntities) {
        List<OrderSettle> result = new ArrayList<>();
        if (orderSettleEntities == null) {
            return result;
        }

        for (OrderSettleEntity orderSettleEntity : orderSettleEntities) {
            OrderSettle orderSettle = entityToDomain(orderSettleEntity);
            result.add(orderSettle);
        }
        return result;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}
